namespace ts_lass_2 {
  /**
   * 类的继承
   * 1. 基本继承：使用 extends 关键字可以让一个类继承另一个类。子类可以继承父类的属性和方法。
   * 2. 调用父类构造函数：在子类的构造函数中，必须首先调用 super()，以初始化父类的属性。super 也可以用来调用父类的方法。
   * 3. 方法重写： 子类可以重写父类的方法
   * 4. 抽象类与抽象方法： 抽象类不能被实例化，只能被继承。抽象方法不能有具体的实现，必须在子类中实现。
   *     -子类必须实现继承抽象类里的所有抽象方法，普通方法可以不实现
   *     -子类可以创建新的方法
   *     -无法创建抽象类的实类，允许创建一个对抽象类型的引用
   * 注：ts中继承父类时构造函数的剩余参数应该用tuple元组类型，具体自己定义（eg. type tuple = [string] ; constructor(public name: string,...args: tuple)
   */

  // 2.1 基本继承
  class Animal {

    constructor(public name: string) { }

    move(distance: number = 0) {  //此处不能加public，只允许在构造函数实现中使用参数属性。
      console.log(`${this.name} is moving ${distance} meters.`);
    }
  }

  class Dog extends Animal {

    bark() {
      console.log("Woof!");
    }
  }

  const dog = new Dog("Rufus");
  dog.bark()  // Woof!
  dog.move(5)  // Rufus is moving 5 meters.

  // 2.2 调用父类构造函数
  type tuple = [string]  // 定义一个元组去接收剩余参数（因为剩余参数的类型有顺序要求）

  class Bird extends Animal {

    constructor(public wingspan: number, ...args: tuple) {  //name: string
      super(...args)
    }

    fly(distance: number) {
      console.log(`${this.name} is flying ${this.wingspan} meters.`);
      super.move(distance)
    }
  }

  const bird = new Bird(20, "Tweety");
  bird.fly(10)  // Tweety is flying 20 meters. Tweety is moving 10 meters.

  // 2.3 方法重写
  class Snake extends Animal {
    // 蛇子类中 重写移动方法
    move(distance: number = 5) {
      console.log('爬呀爬...');
      // 调用父类的移动方法
      super.move(distance); // 调用父类的 move 方法
    }
  }

  const snake = new Snake('Python');
  snake.move();  // 爬呀爬... Python is moving 5 meters. 

  // 2.4 抽象类与抽象方法
  abstract class Animal1 {
    constructor(public name: string) { }

    abstract move(distance: number): void

   printName(): void {
          console.log('Animal1 name:' + this.name);
   }

    
  }

  class Snake1 extends Animal1 {
    constructor() {
      super('蛇')
    }
    move(distance: number): void {
      console.log(`${this.name} 正在蜿蜒地移动...`);
      console.log(`${this.name} 移动了 ${distance} 米。`);
    }
    hiss(): void {
      console.log(`${this.name} 在嘶嘶作响！`);
    }
  }

  let animal1: Animal1  //允许创建一个对抽象类型的引用
  // animal2 = new Animal1() // 报错，不能实例化抽象类
  animal1 = new Snake1()
  animal1.printName() // Animal1 name:蛇
  animal1.move(10) // 蛇 正在蜿蜒地移动... 蛇 移动了 10 米。
  // animal1.hiss() // 报错：类型“Animal1”上不存在属性“hiss”

  const animal2 = new Snake1()
  animal2.printName() // Animal1 name:蛇
  animal2.move(10) // 蛇 正在蜿蜒地移动... 蛇 移动了 10 米。
  animal2.hiss() // 蛇 在嘶嘶作响！

 
}
